home *** CD-ROM | disk | FTP | other *** search
Wrap
//============================================================================== // Scn23p2: AI Scenario Script for scenario 23 player 2 //============================================================================== // // NOTES: Base units to maintain are spearmen and slingers. // At Age 3, slingers are replaced by chariot archers as the base unit. // Mixes include Camelry, Priests, and Anubites. // // Axemen are primarily used as "guard" units on the map, and not sucked into. /* *** DIFFICULTY LEVEL NOTES *** Easy level - Fewer researches. Fewer attacking units. Attacks less frequent and start later. Moderate level - Base level. Difficult - More units on attack and defense, especially sphinxes. Nightmare - More units on attack and defense, especially sphinxes. */ //============================================================================== int difflevel=-1; //============================================================================== // Set Town Location //============================================================================== void setTownLocation(void) { //Look for the "Town Location" marker. kbSetTownLocation(kbGetBlockPosition("3073")); } //============================================================================== // miscStartup //============================================================================== void miscStartup(void) { difflevel=aiGetWorldDifficulty(); //Startup message(s). aiEcho(""); aiEcho(""); aiEcho("Scn06P2 AI Start, filename='"+cFilename+"'."); //Spit out the map size. aiEcho(" Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+")."); aiEcho("Difficulty Level="+difflevel+"."); //Cheat like a bastard. Once only, though. kbLookAtAllUnitsOnMap(); //Calculate some areas. kbAreaCalculate(1200.0); //Set our town location. setTownLocation(); //Reset random seed aiRandSetSeed(); //Allocate all resources to the root escrow. kbEscrowAllocateCurrentResources(); } //============================================================================== //============================================================================== // Attack stuff. //============================================================================== //============================================================================== //Shared variables. int numberAttacks=0; int attackPlayerID=-1; //TODO: Decide how to rep attack group size. int attackMinimumGroupSize=5; int attackMaximumGroupSize=8; //Attack 1 vars. int attackPlan1ID=-1; //Attack 2 vars. int attackPlan2ID=-1; //Maintain plan IDs. int maintainPlan1ID=-1; int maintainPlan2ID=-1; int maintainPlan3ID=-1; // Route and path vars int attackRoute1ID=-1; int attackPath1ID=-1; int attackRoute2ID=-1; int attackPath2ID=-1; // Unit Types int attackerUnitTypeID1=cUnitTypeSpearman; int attackerUnitTypeID2=cUnitTypeSlinger; int attackerUnitTypeID3=cUnitTypePriest; int attackerUnitTypeID4=cUnitTypeSphinx; int attackerUnitTypeID5=cUnitTypeCamelry; int attackerUnitTypeID6=cUnitTypeChariotArcher; int attackerUnitTypeID7=cUnitTypeSiegeTower; bool makingAge3Units=false; int missileMaintainPlan=-1; //========================================================================================= // Kidd's cool configQuery function: used to create attack routes, etc. Oooh, lovin' that! //========================================================================================= bool configQuery( int queryID = -1, int unitType = -1, int action = -1, int state = -1, int player = -1, vector center = vector(-1,-1,-1), bool sort = false, float radius = -1 ) { if ( queryID == -1) { return(false); } if (player != -1) kbUnitQuerySetPlayerID(queryID, player); if (unitType != -1) kbUnitQuerySetUnitType(queryID, unitType); if (action != -1) kbUnitQuerySetActionType(queryID, action); if (state != -1) kbUnitQuerySetState(queryID, state); if (center != vector(-1,-1,-1)) { kbUnitQuerySetPosition(queryID, center); if (sort == true) kbUnitQuerySetAscendingSort(queryID, true); if (radius != -1) kbUnitQuerySetMaximumDistance(queryID, radius); } return(true); } //============================================================================== // Check for number of AI units near the enemy TC. // Used to fire off eclipse - should happen fairly early //============================================================================== int checkForEclipse(void) { static int eclipseQueryID=-1; vector enemyBase=kbGetBlockPosition("3082"); int unitCount=-1; if (eclipseQueryID < 0) { // Doesn't exist, set it up eclipseQueryID = kbUnitQueryCreate("Eclipse Query"); // Get the number if ( configQuery( eclipseQueryID, cUnitTypeUnit, -1, cUnitStateAlive, 2, enemyBase, false, 20 ) == false ) return(-1); } kbUnitQueryResetResults(eclipseQueryID); unitCount = kbUnitQueryExecute(eclipseQueryID); return(unitCount); } //============================================================================== // Check for number of player units near the pyramid. // Used to fire off Ancestors (if Age 3, duh) //============================================================================== int checkForAncestors(void) { static int ancestorsQueryID=-1; vector pyramidLocation=kbGetBlockPosition("3073"); int unitCount=-1; if (ancestorsQueryID < 0) { // Doesn't exist, set it up ancestorsQueryID = kbUnitQueryCreate("Ancestors Query"); // Get the number if ( configQuery( ancestorsQueryID, cUnitTypeUnit, -1, cUnitStateAlive, 1, pyramidLocation, false, 20 ) == false ) return(-1); } kbUnitQueryResetResults(ancestorsQueryID); unitCount = kbUnitQueryExecute(ancestorsQueryID); return(unitCount); } //============================================================================== // initAttack: Creates attack routes, etc. //============================================================================== void initAttack(int playerID=-1) { //Destroy all previous attacks (if this isn't the player we're already attacking. if (playerID != attackPlayerID) { //Reset the attack player ID. attackPlayerID=-1; //Destroy any previous attack plan. aiPlanDestroy(attackPlan1ID); attackPlan1ID=-1; aiPlanDestroy(attackPlan2ID); attackPlan2ID=-1; //Destroy our previous attack paths. kbPathDestroy(attackPath1ID); attackPath1ID=-1; kbPathDestroy(attackPath2ID); attackPath2ID=-1; //Destroy our previous attack routes. attackRoute1ID=-1; attackRoute2ID=-1; //Reset the number of attacks. numberAttacks=0; } //Save the player to attack. attackPlayerID=playerID; vector gatherPoint1=kbGetBlockPosition("3073"); vector gatherPoint2=kbGetBlockPosition("3074"); //Setup attack path 1 - go left attackPath1ID=kbPathCreate("Attack Path 1"); kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3075")); kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3076")); //Create attack route 1. attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint1, kbGetBlockPosition("3077")); if (attackRoute1ID >= 0) kbAttackRouteAddPath(attackRoute1ID, attackPath1ID); //Setup attack path 2 - go right attackPath2ID=kbPathCreate("Attack Path 2"); kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3078")); kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3079")); kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3080")); kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3081")); //Create attack route 2. attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPoint2, kbGetBlockPosition("3082")); if (attackRoute2ID >= 0) kbAttackRouteAddPath(attackRoute2ID, attackPath2ID); } //============================================================================== // setupAttack1 (primarily spearmen) //============================================================================== bool setupAttack1(int playerID=-1) { int randomPath=aiRandInt(2); int randomUnits=aiRandInt(4); //Info. aiEcho("Attacking Player "+playerID+"."); //If the player to attack doesn't match, init the attack. if (attackPlayerID != playerID) { initAttack(playerID); if (attackPlayerID < 0) return(false); } //Create an attack plan. int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack); if (newAttackPlanID < 0) return(false); //Target player (required). This must work. if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false) return(false); //Gather point. vector gatherPoint=kbGetBlockPosition("3073"); //Set the target type. This must work. if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false) return(false); //Unit types to attack. aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeBuilding); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit); //Attack route. if (randomPath == 0) { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID); aiEcho("Attack going left."); } else { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID); aiEcho("Attack going right."); } //Set the gather point and gather point distance. aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint); aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 20.0); //Set up the attack route usage pattern. aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom); //Add the primary unit type to the plan. aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize); // Add a sphinx usually, but only if we're going right. if ( randomUnits < 3 && randomPath == 1 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 1, 1); } // Randomly add two slingers, if available (rare, and only early). if ( randomUnits == 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 0, 2, 2); } // If we're making Age 3 units, we don't need the priests for the other attack, so use a couple of them here. // Also add a siege tower if available. if ( makingAge3Units == true ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 2, 2); aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID7, 0, 1, 3); // Randomly add two chariot archers, if available. if ( randomUnits == 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2); } } //Set the initial position. aiPlanSetInitialPosition(newAttackPlanID, gatherPoint); //Plan requires all need units to work (can be false). aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true); //Activate the plan. aiPlanSetActive(newAttackPlanID); //Now, save the attack plan ID appropriately. aiPlanSetOrphan(attackPlan1ID, true); attackPlan1ID=newAttackPlanID; //Increment our overall number of attacks. numberAttacks++; } //============================================================================== // setupAttack2 //============================================================================== bool setupAttack2(int playerID=-1) { int randomPath=aiRandInt(2); int randomUnits=aiRandInt(4); //Info. aiEcho("Attacking Player "+playerID+"."); //If the player to attack doesn't match, init the attack. if (attackPlayerID != playerID) { initAttack(playerID); if (attackPlayerID < 0) return(false); } //Create an attack plan. int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack); if (newAttackPlanID < 0) return(false); //Target player (required). This must work. if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false) return(false); //Gather point. vector gatherPoint=kbGetBlockPosition("3074"); //Set the target type. This must work. if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false) return(false); //Unit types to attack. aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding); //Attack route. if (randomPath == 0) { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID); aiEcho("Attack going left."); } else { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID); aiEcho("Attack going right."); } //Set the gather point and gather point distance. aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint); aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 20.0); //Set up the attack route usage pattern. aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom); //Add the unit types to the plan - which main type depends on what we're maintaining. if ( makingAge3Units == true ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize); // Randomly throw two to four camels in for fun 40% of the time. Don't go if you don't have at least two. if ( randomUnits < 2 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 2, 2, 4); } // If no camels, then sphinxes are likely, but only if we're going right. if ( randomUnits < 3 && randomPath == 1 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 4, 4); } // Siege towers. If available. aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID7, 0, 4, 4); } else { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize); // Add two spearmen, if available, half the time. if ( randomUnits < 2 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, 0, 2, 2); } // Possibly one priest; if not, then a siege tower (or two). if ( randomUnits > 1 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 1, 1); } else { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID7, 0, 4, 4); } // Rarely a Sphinx, but only if we're going right. if ( randomUnits == 1 && randomPath == 1) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 1, 2); } } //Set the initial position. aiPlanSetInitialPosition(newAttackPlanID, gatherPoint); //Plan requires all need units to work (can be false). aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true); //Activate the plan. aiPlanSetActive(newAttackPlanID); //Now, save the attack plan ID appropriately. aiPlanSetOrphan(attackPlan2ID, true); attackPlan1ID=newAttackPlanID; //Increment our overall number of attacks. numberAttacks++; } //============================================================================== // Age 2 Tech Research Rules - medium slingers, spearmen, and criosphinx //============================================================================== rule researchMediumSlingers minInterval 240 active { int planID=aiPlanCreate("Medium Spearman research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechMediumSlingers); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchMediumSpearmen minInterval 300 active { int planID=aiPlanCreate("Medium Spearman research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechMediumSpearmen); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchCriosphinx minInterval 600 active { int planID=aiPlanCreate("Criosphinx research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechCriosphinx); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeTemple); aiPlanSetActive(planID); //Done. xsDisableSelf(); } //============================================================================== // Age 3 Tech Research Rules - activated by the Age 3 advancement thing //============================================================================== rule researchHeavySpearmen minInterval 120 inactive { int planID=aiPlanCreate("Heavy Spearman research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechHeavySpearmen); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchBronzeShields minInterval 180 inactive { int planID=aiPlanCreate("Bronze Shields research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeShields); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchBronzeWeapons minInterval 240 inactive { int planID=aiPlanCreate("Bronze Weapons research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeWeapons); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchHeavyChariots minInterval 240 inactive { int planID=aiPlanCreate("Heavy Chariot research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechHeavyChariots); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeMigdolStronghold); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchBronzeMail minInterval 360 inactive { int planID=aiPlanCreate("Bronze Mail research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeMail); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory); aiPlanSetActive(planID); //Done. xsDisableSelf(); } //============================================================================== // Attack Generator 1 - First Attack Plan //============================================================================== rule attackGenerator1 minInterval 90 inactive group AttackRules { //See how many "idle" attack plans we have. Don't create any more if we have //idle plans. int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack); if (numberIdleAttackPlans > 0) return; //If we have enough unassigned military units, create a new attack plan. int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1); aiEcho("There are "+numberAvailableUnits+" spearmen available for a new attack."); if (numberAvailableUnits >= attackMinimumGroupSize) setupAttack1(1); } //============================================================================== // Attack Generator 2 - Second Attack Plan //============================================================================== rule attackGenerator2 minInterval 105 inactive group AttackRules { //See how many "idle" attack plans we have. Don't create any more if we have //idle plans. int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack); if (numberIdleAttackPlans > 0) return; //If we have enough unassigned military units of the primary type, create a new attack plan. int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID2); if ( makingAge3Units == true ) { numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID6); } aiEcho("There are "+numberAvailableUnits+" slingers/chariot archers available for a new attack."); if (numberAvailableUnits >= attackMinimumGroupSize) setupAttack2(1); } //============================================================================== // Attack enablers - enable attacks once timers expire //============================================================================== rule attack1Enabler minInterval 90 active group AttackRules { xsEnableRule("attackGenerator1"); xsDisableSelf(); } rule attack2Enabler minInterval 120 active group AttackRules { xsEnableRule("attackGenerator2"); xsDisableSelf(); } //===================================================================================== // 90 seconds after starting to research Age 3, set things up. // ...start maintaining anubites and camelry. // ...and switch to Chariot Archers instead of slingers. // ...and activate a bunch of other rules, researches, etc. //===================================================================================== rule age3Setup minInterval 90 inactive group AttackRules { difflevel=aiGetWorldDifficulty(); int age3Active = kbGetTechStatus( cTechAge3Nephthys ); int camelryMaintained = 4; //Share the number to maintain. int numberToMaintain=attackMinimumGroupSize*2; vector gatherPointLeft=kbGetBlockPosition("3073"); vector gatherPointRight=kbGetBlockPosition("3074"); // Verify we're actually where we need to be, then maintain away. if (age3Active == cTechStatusActive ) { int maintainPlan1ID=aiPlanCreate("Maintain "+camelryMaintained+" "+kbGetProtoUnitName(attackerUnitTypeID5), cPlanTrain); if (maintainPlan1ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID5 ); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, camelryMaintained); //Don't train units faster than every 30 seconds aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 30); //Set a gather point. aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointRight); //Activate the plan. aiPlanSetActive(maintainPlan1ID); } // For missile units, destroy the original plan and make a new one. aiPlanDestroy( missileMaintainPlan ); // Chariot archers, baby! int maintainPlan2ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID6), cPlanTrain); if (maintainPlan2ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID6); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); //Don't train units faster than every 35 seconds aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 35); //Set a gather point. aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointRight); //Activate the plan. aiPlanSetActive(maintainPlan2ID); } // Set a shared boolean so we know to add fun stuff to our attack groups. makingAge3Units = true; // Enable a bunch of research rules on everything other than Easy. if ( difflevel > 0 ) { xsEnableRule("researchHeavySpearmen"); xsEnableRule("researchHeavyChariots"); xsEnableRule("researchBronzeShields"); xsEnableRule("researchBronzeWeapons"); xsEnableRule("researchBronzeMail"); } aiEcho("Now maintaining Age 3 units."); //Done, disable. xsDisableSelf(); } } //================================================================================================ // Advance to Age 3 ten minutes into the game. This in turn fires off tons o' stuff. //================================================================================================ rule researchAge3 minInterval 600 inactive { int planID=aiPlanCreate("Advancing to Age 3 (Nephthys)", cPlanResearch); if (planID < 0) return; aiEcho("*** ADVANCING TO AGE 3 ***"); aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechAge3Nephthys); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeCitadelCenter); aiPlanSetActive(planID); // Now maintain Age 3 stuff. xsEnableRule("age3Setup"); // Done. xsDisableSelf(); } //============================================================================== // GOD POWER USAGE //============================================================================== rule fireEclipse minInterval 15 active group AttackRules { int numAttackers=-1; vector eclipsePoint=kbGetBlockPosition("3074"); numAttackers=checkForEclipse(); if (numAttackers > 4) { aiEcho("Close to enemy town with group, fire Eclipse."); if ( aiCastGodPowerAtPosition(cTechEclipse, eclipsePoint) == true ) xsDisableSelf(); else aiEcho("Eclipse failed - try again later."); } } rule fireAncestors minInterval 10 active group AttackRules { int numAttackers=-1; vector ancestorsPoint=kbGetBlockPosition("3073"); numAttackers=checkForAncestors(); if (numAttackers > 4) { aiEcho("Enemy units coming in, fire Ancestors."); if ( aiCastGodPowerAtPosition(cTechSkeletonPower, ancestorsPoint) == true ) xsDisableSelf(); else aiEcho("Ancestors failed - try again later."); } } //============================================================================== // MAIN. //============================================================================== void main(void) { difflevel=aiGetWorldDifficulty(); //Startup. miscStartup(); int sphinxesMaintained = 4; // Difficulty Level Adjustments if ( difflevel == 0 ) { xsSetRuleMinInterval( "attack1Enabler", 210 ); xsSetRuleMinInterval( "attack2Enabler", 240 ); xsSetRuleMinInterval( "attackGenerator2", 150 ); } if ( difflevel == 2 ) { sphinxesMaintained = 6; attackMinimumGroupSize=7; attackMaximumGroupSize=9; xsSetRuleMinInterval( "researchAge3", 120 ); } else if ( difflevel == 3 ) { sphinxesMaintained = 8; attackMinimumGroupSize=9; attackMaximumGroupSize=12; xsSetRuleMinInterval( "researchAge3", 10 ); } xsEnableRule("researchAge3"); //Share the number to maintain. int numberToMaintain=attackMinimumGroupSize*2; //Two possible gather points. vector gatherPointLeft=kbGetBlockPosition("3073"); vector gatherPointRight=kbGetBlockPosition("3074"); vector gatherPointSphinx=kbGetBlockPosition("3079"); vector gatherPointTowers=kbGetBlockPosition("2380"); //Create a simple plan to maintain X spearmen. int maintainPlan1ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain); if (maintainPlan1ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); //Don't train units faster than every 25 seconds aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 25); //Set a gather point. aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointLeft); //Activate the plan. aiPlanSetActive(maintainPlan1ID); } //Create a simple plan to maintain X slingers. int maintainPlan2ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain); if (maintainPlan2ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); //Don't train units faster than every 35 seconds aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 35); //Set a gather point. aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointRight); //Activate the plan. aiPlanSetActive(maintainPlan2ID); //Store off the plan in a variable so we can modify this sucker later. //DAL - I wonder if this will work... missileMaintainPlan=maintainPlan2ID; } //Create a simple plan to maintain 3 priests. int maintainPlan3ID=aiPlanCreate("Maintain 3 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain); if (maintainPlan3ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3); //You can limit the number of units that are ever trained by this plan with this call. //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 3); //Don't train units faster than every 75 seconds aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 75); //Set a gather point. aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointRight); //Activate the plan. aiPlanSetActive(maintainPlan3ID); } // And sphinxes. Sphinxes are cool. They don't go out to join attacks very often, though. int maintainPlan4ID=aiPlanCreate("Maintain "+sphinxesMaintained+" "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain); if (maintainPlan4ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4); //Makes total of fifteen, then stops. Player deserves a break. aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToTrain, 0, 15); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, sphinxesMaintained); //Don't train units faster than every three minutes aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 180); if ( difflevel > 1 ) { aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 90); } //Set a gather point. aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPointSphinx); //Activate the plan. aiPlanSetActive(maintainPlan4ID); } // One more. Keep a siege tower handy at all times. More on Hard and Titan. int maintainPlan5ID=aiPlanCreate("Maintain 1 "+kbGetProtoUnitName(attackerUnitTypeID7), cPlanTrain); if (maintainPlan5ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanUnitType, 0, attackerUnitTypeID7); //Makes total of twenty, then stops. Player deserves a break. aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToTrain, 0, 20); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 1); //Don't train units faster than every 60 seconds aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 60); if ( difflevel == 2 ) { aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 3); aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 20); } if ( difflevel == 3 ) { aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 5); aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 10); } //Set a gather point. aiPlanSetVariableVector(maintainPlan5ID, cTrainPlanGatherPoint, 0, gatherPointTowers); //Activate the plan. aiPlanSetActive(maintainPlan5ID); } }